#include <iostream>
#include <string>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

//事先不知道接收多少字节，循环接收知道接收完
int MyRecv(int iSock, char *pchBuf, size_t tCount)
{
    size_t tBytesRead = 0;
    int iThisRead;
    while (tBytesRead < tCount)
    {
        do
        {
            iThisRead = read(iSock, pchBuf, tCount - tBytesRead);
        } while ((iThisRead < 0) && (errno == EINTR));
        if (iThisRead < 0)
        {
            return iThisRead;
        }
        else if (iThisRead == 0)
        {
            return tBytesRead;
        }
        tBytesRead += iThisRead;
        pchBuf += iThisRead;
    }
    return 0;
}

#define DEFAULT_PORT 6666

int main(int argc, char **argv)
{
    // 监听socket：sockfd，数据传输socket：acceptfd
    int sockfd, acceptfd;
    // 本地地址信息
    struct sockaddr_in my_addr;
    // 客户地址信息
    struct sockaddr_in their_addr;
    unsigned int sin_size, myport = 6666, lisnum = 10;
    // 绑定端口和准备收包
    //  根据地址类型创建了一个TCP的socket，如果出错打印出错码
    //  socket参数：(协议域如ipv4，socket类型如tcp，指定协议若0时自动选择)
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket ");
        return -1;
    }
    cout << "socket ok " << endl;
    my_addr.sin_family = AF_INET;
    // INADDR_ANY一般指定系统中的0.0.0.0地址
    my_addr.sin_port = htons(DEFAULT_PORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(my_addr.sin_zero), 0);
    // 将地址绑定在listenfd上
    // bind参数：(socket描述字，一个const struct sockaddr*指针指向要绑定socketfd的协议地址)
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    {
        perror("bind ");
        return -2;
    }
    cout << "bind ok " << endl;
    // 监听这个listenfd，若客户端调用connect()发出请求，服务器端就会收到
    // listen参数：(要监听的socket描述字，相应socket可以排队的最大连接个数)
    if (listen(sockfd, lisnum) == -1)
    {
        perror("listen ");
        return -3;
    }
    cout << "listen ok " << endl;
    char recvMsg[10];
    sin_size = sizeof(my_addr);
    acceptfd = accept(sockfd, (struct sockaddr *)&my_addr, &sin_size);
    if (acceptfd < 0)
    {
        close(sockfd);
        cout << "accept failed" << endl;
        return -4;
    }
    // 需要先接收4个字节，转换成主机序，才能知道接下来是接收多少字节的数据
    ssize_t readLen = MyRecv(acceptfd, recvMsg, sizeof(int));
    if (readLen < 0)
    {
        cout << "read failed" << endl;
        return -1;
    }
    int len = (int)ntohl(*(int *)recvMsg);
    cout << "len: " << len << endl;
    readLen = MyRecv(acceptfd, recvMsg, len);
    if (readLen < 0)
    {
        cout << "read failed" << endl;
        return -1;
    }
    recvMsg[len] = '\0';
    cout << "recvMsy: " << recvMsg << endl;
    close(acceptfd);
    return 0;
}
